Imports System.Data.SqlClient

Namespace DbConnection.Impl


    ''' <summary>
    ''' decacorator which doesn't fire twice the same query
    ''' </summary>
    ''' <remarks></remarks>
    ''' 
    Public Class TCacheConnection
        Implements IConnection


        Private _connection As IConnection

        Private _memory As New Hashtable

        Public Sub New()

        End Sub

        Public Sub close() Implements IConnection.close
            _memory = Nothing
            _connection.close()
        End Sub

        Private Sub ClearCache()
            _memory = New Hashtable()
        End Sub

        Public Function executeNonQuery(ByVal query As String, ByVal ParamArray parameters() As System.Data.SqlClient.SqlParameter) As Integer Implements IConnection.executeNonQuery
            'this meam a change in db
            ClearCache()
            Return _connection.executeNonQuery(query, parameters)
        End Function

        Private Function isValidQuery(ByVal query As String) As Boolean
            Dim p_number As Integer = 0
            For Each c As Char In query

                If c = ")" Then
                    p_number -= 1
                    If p_number < 0 Then Return False
                End If

                If c = "(" Then p_number += 1
            Next
            Return True
        End Function

        Private Function cleanQuery(ByVal query As String) As String
            Dim result As String = query.Trim
            result = result.ToLower
            If result.StartsWith("(") AndAlso result.EndsWith(")") Then
                Dim possibile As String = result.Substring(1, result.Length - 2)
                If isValidQuery(possibile) Then result = possibile
            End If
            If result <> query Then
                Return cleanQuery(result)
            Else
                Return query
            End If
        End Function


        Private Function generateKey(ByVal query As String, ByVal ParamArray parameters() As System.Data.SqlClient.SqlParameter) As String
            query = cleanQuery(query)
            For Each p As SqlParameter In parameters
                Dim value As Object = p.Value
                Dim pvalue As String
                If value Is Nothing Then
                    pvalue = "Nothing"
                Else
                    pvalue = value.ToString
                End If
                Dim pname As String = p.ParameterName.ToLower
                If Not pname.StartsWith("@") Then pname = "@" + pname
                query = query.Replace(pname, pvalue)
            Next

            Return query

        End Function


        Private Sub servingFromCache()
            ' TRACE LOGGING REMOVED [Leave this comment to allow find replace re-addition of trace logging]
        End Sub

        Public Function executeQuery(ByVal query As String, ByVal ParamArray parameters() As System.Data.SqlClient.SqlParameter) As DataTable Implements IConnection.executeQuery
            Dim key As String = generateKey(query, parameters)
            Dim cache_result As DataTable = DirectCast(Me._memory(key), DataTable)
            If cache_result IsNot Nothing Then
                servingFromCache()
                Return cache_result
            End If

            ' TRACE LOGGING REMOVED [Leave this comment to allow find replace re-addition of trace logging]

            Dim result As DataTable = _connection.executeQuery(query, parameters)
            Me._memory(key) = result
            Return result
        End Function

        Public Function executeScalar(ByVal query As String, ByVal ParamArray parameters() As System.Data.SqlClient.SqlParameter) As Object Implements IConnection.executeScalar
            Return _connection.executeScalar(query, parameters)
        End Function

        Public Function executeFileScript(ByVal filePath As String) As Integer Implements IConnection.executeFileScript
            'this meam a change in db
            ClearCache()
            Return _connection.executeFileScript(filePath)
        End Function

        Public Sub setDecorated(ByVal o As IConnection)
            _connection = o
        End Sub
    End Class

End Namespace

